package org.dpes.apriori;

import java.util.Arrays;

public class HashTab {

	private static float UPGRADE_FACTOR = 0.2f;

	private int eval;

	private long[][] hashTable;

	private int[] availableSpace;

	private int[] currentIndex;
	
	private int size = 0;

	private void guaranteeFreeSpace(int hash) {

		if (availableSpace[hash] - currentIndex[hash] > 0)
			;
		else {
			resizeSlot(hash);
		}
	}

	private void resizeSlot(int hash) {
		int newSize = availableSpace[hash]
				+ (int) (availableSpace[hash] * UPGRADE_FACTOR);

		long[] newSlot = new long[newSize];

		System.arraycopy(hashTable[hash], 0, newSlot, 0, availableSpace[hash]);

		hashTable[hash] = newSlot;

		availableSpace[hash] = newSize;
	}

	/*
	 * public API :
	 */

	public HashTab(int nEval) {
		eval = nEval / HashLib.NUM_OF_SOCKETS;

		if (eval == 0)
			eval = 10;

		hashTable = new long[HashLib.NUM_OF_SOCKETS][eval];
		availableSpace = new int[HashLib.NUM_OF_SOCKETS];
		currentIndex = new int[HashLib.NUM_OF_SOCKETS];

		Arrays.fill(availableSpace, eval);
	}
	
	public boolean insert(long val) {
		boolean ret = put(val);
		if (ret)
			size++;
		return ret;
	}
	
	private boolean put(long val) {

		int hash = Math.abs(HashLib.getValue(val));
		
		guaranteeFreeSpace(hash);
		
		if (currentIndex[hash] > 1) {

			int result = Arrays.binarySearch(hashTable[hash], 0,
					currentIndex[hash], val);

			if (result < 0) {
				
				int indexForVal = Math.abs(result) - 1;
				if (indexForVal == currentIndex[hash]) {
					hashTable[hash][currentIndex[hash]++] = val;
					return true;
				}
				
				System.arraycopy(hashTable[hash], indexForVal, hashTable[hash],
						indexForVal + 1, currentIndex[hash] - indexForVal);
				

				currentIndex[hash]++;
				hashTable[hash][indexForVal] = val;
				
				return true;

			} else {
				return false;
			}
		}

		if (currentIndex[hash] == 0) {
			hashTable[hash][currentIndex[hash]++] = val;
			return true;
		}
		
		if (currentIndex[hash] == 1) {
			if (hashTable[hash][0] == val)
				return false;
			
			else if (hashTable[hash][0] < val) {
				hashTable[hash][currentIndex[hash]++] = val;
				return true;
			} else {
				hashTable[hash][1] = hashTable[hash][0];
				hashTable[hash][0] = val;
				currentIndex[hash]++;
				return true;
			}
		}

		throw new RuntimeException("Illegal State Exception !!!");
	}

	public boolean isThere(long val) {

		int hash = Math.abs(HashLib.getValue(val));
		
		if (currentIndex[hash] > 1) {

			int result = Arrays.binarySearch(hashTable[hash], 0,
					currentIndex[hash], val);
			if (result < 0)
				return false;
			return true;
		}

		if (currentIndex[hash] == 0)
			return false;

		if (currentIndex[hash] == 1) {
			if (hashTable[hash][0] == val)
				return true;
			else
				return false;
		}

		throw new RuntimeException("Illegal State Exception !!!");
	}
	
	public int size() {
		return size;
	}

	@Override
	protected void finalize() throws Throwable {
		//System.out.println("zwalniam HashTab.");
	}
	
}
